package classfile

import (
	"regexp"
)

// 代表字段或者方法的公共结构体
type MemberInfo struct {
	// 对常量池的指针
	cp ConstantPool
	// 访问标志，标志是否public，是否private，是否静态、是否final等信息
	accessFlag uint16
	// 对常量池的有效索引，常量池此位置必须是UTF8结构，代表此字段或方法的名称
	nameIndex uint16
	// 对常量池的有效索引，常量池此位置必须是UTF8结构，代表此字段或方法的描述符
	descriptorIndex uint16
	// 此字段或者方法的属性。很多属性都可以出现在这里，最常见的就是将字段或者方法标记为已过期的属性deprecated
	attributes []AttributeInfo
}

func readMembers(reader *ClassReader, cp ConstantPool) []*MemberInfo {
	// 字段和方法都是由两字节指定长度，然后再读取实际的数组
	memberCount := reader.ReadUint16()
	members := make([]*MemberInfo, memberCount)
	for i := range members {
		members[i] = readMember(reader, cp)
	}
	return members
}
func readMember(reader *ClassReader, cp ConstantPool) *MemberInfo {
	return &MemberInfo{
		cp:              cp,
		accessFlag:      reader.ReadUint16(),
		nameIndex:       reader.ReadUint16(),
		descriptorIndex: reader.ReadUint16(),
		attributes:      readAttributes(reader, cp),
	}
}
func (self *MemberInfo) AccessFlags() uint16 {
	return self.accessFlag
}
func (self *MemberInfo) Name() string {
	return self.cp.getUtf8(self.nameIndex)
}
func (self *MemberInfo) Descriptor() string {
	return self.cp.getUtf8(self.descriptorIndex)
}

// 查找Code属性，只有方法会有这个属性
func (self *MemberInfo) CodeAttributor() *CodeAttribute {
	// 遍历所有属性，遇到code属性就返回
	for _, attrInfo := range self.attributes {
		switch attrInfo.(type) {
		case *CodeAttribute:
			return attrInfo.(*CodeAttribute)
		}
	}
	return nil
}

// 查找常量值属性，只有字段会有这个属性
func (self *MemberInfo) ConstantValueAttribute() *ConstantValueAttribute {
	for _, attr := range self.attributes {
		switch attr.(type) {
		case *ConstantValueAttribute:
			return attr.(*ConstantValueAttribute)
		}
	}
	return nil
}

type MethodDescriptor struct {
	ParameterTypes []string
	ReturnType     string
}



// descriptor的格式类似于([Ljava/lang/Object;Ljava/util/List;)Ljava/lang/Object;
func  ParseMethodDescription(descriptor string) *MethodDescriptor {
	var paramTypes []string

	// 匹配被括号包裹的内容
	paramStringMatcher := regexp.MustCompile(`^\((.*)\)(.+?);?$`)

	// 查找所有匹配项
	paramStringMatchs := paramStringMatcher.FindAllStringSubmatch(descriptor, -1)
	for _, match := range paramStringMatchs {
		// 括号里面的内容就是方法参数
		paramTypeString := match[1]
		// 括号后面的内容是返回值类型
		returnType := match[2]



		// 将多个方法参数都提取出来
		oneParamMatcher := regexp.MustCompile(`(\[*([ZBCSIJFD]|L[^;]+))`)
		//oneParamMatcher := regexp.MustCompile(`(\[*(Z|B|C|S|I|J|F|D|L.+?;))`)
		paramMatchs := oneParamMatcher.FindAllStringSubmatch(paramTypeString, -1)
		for _, oneParam := range paramMatchs {
			//arg := strings.Trim(oneParam[1],";")
			arg := oneParam[1]
			//fmt.Println("方法参数"+ strconv.Itoa(index) + ":    "+arg)
			paramTypes = append(paramTypes, arg)
		}
		//fmt.Println("方法返回:    "+returnType)
		result := &MethodDescriptor{
			ParameterTypes: paramTypes,
			ReturnType:     returnType,
		}
		return result
	}

	panic("方法描述格式错误[" + descriptor + "]")
}
